from PyQt5.QtCore import Qt, QDate, QEvent, QTimer, QStringListModel
from PyQt5.QtWidgets import QLineEdit, QComboBox, QMainWindow, QWidget, QCompleter

from ui.invoicePrinterUI import Ui_MainWindow
from ui.tableview import TableView
from utils.define import *
from blinker import Signal
from utils.tools import *


class nameCompleter(QCompleter):
    #TODO： 更优雅的方式
    listInfo = None
    def __init__(self, parent=None):
        super(nameCompleter, self).__init__(parent)
        self.setFilterMode(Qt.MatchStartsWith)
        self.setModel(QStringListModel(self.listInfo or []))


# 名称用来快速输入
class numToName:
    _dict = None

    @staticmethod
    def setDict(data):
        numToName._dict = data

    @staticmethod
    def clacName(uiName):
        def doFormula(formula):
            return numToName._dict.get(formula) or numToName._dict.get(str(formula)) or formula

        text = ""
        formula = ""
        for char in uiName.text():
            if char.isdigit():
                formula += char
            else:
                if formula != "":
                    text += doFormula(formula)
                    formula = ""
                text += char
        if formula != "":
            text += doFormula(formula)
        uiName.setText(text)

# 每一行作为一个UI组件设置自动填充、自动计算等功能
class UIItem:
    n2UFunc = None

    # 每项列 {名称name 单位unit 数量num 单价unitPrice 金额price 备注note}
    def __init__(self, idCount, name: QLineEdit, unit, num, unitPrice, price, note):
        self.id = idCount
        self.name = name
        self.unit = unit
        self.num = num
        self.unitPrice = unitPrice
        self.price = price
        self.note = note

        self.num.editingFinished.connect(self.calcPrice)
        self.unitPrice.editingFinished.connect(self.calcPrice)
        def handleReturnPressed():
            numToName.clacName(self.name)
            self.nameCompleter.setCompletionPrefix(self.name.text())
            self.nameCompleter.complete()
        self.name.returnPressed.connect(handleReturnPressed)
        self.nameCompleter = nameCompleter(self.name)
        self.name.setCompleter(self.nameCompleter)
        # 直接显示价格
        def setPrice():
            self.unitPrice.setText("")
            prices = self.n2UFunc(self.name.text())
            if len(prices) > 0:
                self.unitPrice.setText(prices[0])
        self.name.editingFinished.connect(setPrice)
        # 默认单位：米
        self.name.editingFinished.connect(lambda: self.unit.setText("米"))

        self._upcompleterActive = False
        def setPriceEvent():
            if not self._upcompleterActive:
                self._upcompleterActive = True

                name = self.name.text()
                if len(self.n2UFunc(name)) > 1:
                    self.unitPriceCompleter.setModel(QStringListModel(self.n2UFunc(name)))
                    self.unitPriceCompleter.complete()

                QTimer.singleShot(100, lambda: setattr(self, "_upcompleterActive", False))
            return True

        self.unitPrice.mousePressEvent = lambda event: setPriceEvent() and QLineEdit.mousePressEvent(self.unitPrice, event)
        self.unitPrice.focusInEvent = lambda event: setPriceEvent() and QLineEdit.focusInEvent(self.unitPrice, event)

        self.unitPriceCompleter = QCompleter(self.unit)
        self.unitPrice.setCompleter(self.unitPriceCompleter)
        # self.name.cursorPositionChanged.connect(lambda: print("edit", self.id))

    def __getitem__(self, item):
        if item in ITEM:
            if item == "id":
                return self.id
            ui = getattr(self, item)
            return ui.text()

    def clear(self):
        self.name.setText("")
        self.unit.setText("")
        self.num.setText("")
        self.unitPrice.setText("")
        self.price.setText("")
        self.note.setText("")

    def calcPrice(self):
        numText = self.num.text().strip()
        unitPriceText = self.unitPrice.text().strip()

        self.num.setText(numText)
        self.unitPrice.setText(unitPriceText)

        if numText == "" and unitPriceText == "":
            return True

        if "=" in numText:
            try:
                # 备注显示计算内容
                self.note.setText(numText.replace("=", ""))

                numText = strRound2(eval(numText.replace("=", "")))
                self.num.setText(numText)
            except Exception as e:
                showMessageBox(str(self.id) + "行数量输入错误")
        if "=" in unitPriceText:
            try:
                unitPriceText = strRound2(eval(unitPriceText.replace("=", "")))
                self.unitPrice.setText(unitPriceText)
            except Exception as e:
                showMessageBox(str(self.id) + "行单价输入错误")

        if isdigit(numText) and isdigit(unitPriceText):
            if float(unitPriceText) > 30:
                showMessageBox(str(self.id) + "行单价>30元")
                return False

            result = float(numText) * float(unitPriceText)
            self.price.setText("{:.2f}".format(result))
            return True
        return False

    @staticmethod
    def setN2UFunc(func):
        UIItem.n2UFunc = func


def initUIItemList(ui: Ui_MainWindow):
    items = []
    for i in range(1, 7):
        item = UIItem(
            i,
            getattr(ui, f"lineEdit_name{i}"),
            getattr(ui, f"lineEdit_unit{i}"),
            getattr(ui, f"lineEdit_num{i}"),
            getattr(ui, f"lineEdit_unitPrice{i}"),
            getattr(ui, f"lineEdit_price{i}"),
            getattr(ui, f"lineEdit_note{i}")
        )
        items.append(item)
    return items

class TimerManager:
    def __init__(self, timeout_callback, interval):
        self.timer = QTimer()
        self.timer.setInterval(interval)
        self.timer.timeout.connect(timeout_callback)

    def start(self):
        self.timer.start()

    def reset(self):
        self.timer.stop()
        self.timer.start()

class MainWindow(QMainWindow):
    def __init__(self, controller):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.controller = controller
        self.show()
        self.registerEventFilter()

        self.timer = TimerManager(self.close, CLOSE_TIME)
        self.timer.start()

    def closeEvent(self, event):
        if self.controller.close():
            event.accept()
        else:
            event.ignore()

    def registerEventFilter(self):
        self.installEventFilter(self)
        for widget in self.findChildren(QWidget):
            widget.installEventFilter(self)

    def eventFilter(self, obj, event):
        if event.type() in [QEvent.MouseButtonPress, QEvent.KeyPress]:
            self.timer.reset()
        return False


class UIModel():
    onNameChanged = Signal(str)

    def __init__(self, controller):
        self.controller = controller
        self.mainWindow = MainWindow(controller)
        ui = self.mainWindow.ui
        # 编号
        self.id = ui.lineEdit_id
        # 手机
        self.mobile = ui.lineEdit_mobile
        # 厂电
        # self.phone = None
        # 收款单位
        self.money = ui.lineEdit_money
        # 收货单位
        self.goods = ui.lineEdit_goods
        # 客户名称
        self.customer = ui.combox_customer
        # 开票日期
        self.date = ui.dateTime
        # 条目(最多六项)
        nameCompleter.listInfo = self.controller.config.nameList
        self.items = initUIItemList(ui)

        # 表
        self.tableView = TableView(ui.tableView, self)

        # 新增客户
        self.btnAddInCustomer = ui.btn_addInCustomer
        self.btnAddOutCustomer = ui.btn_addOutCustomer
        # 清空数据
        self.btnClearItems = ui.btn_clearItems
        # 打印并保存按钮
        self.btnPrint = ui.btn_printView
        # 打印按钮
        self.btnSave = ui.btn_save

        # 显示总计
        self.sumPrice = ui.label_sumPrice
        self.sumPriceMonth = ui.label_sumPriceMonth

        self.setUI()
        self.bindEvents()

    def setUI(self):
        UIItem.setN2UFunc(self.controller.getpriceFunc())
        numToName.setDict(self.controller.getNum2NameDict())
        # 设置使用者信息
        self.mobile.setText(self.controller.getUserMobile())
        self.money.setText(self.controller.getUserName())

        # 设置日期
        self.date.setDate(QDate().currentDate())
        # 设置id序号
        self.id.setText(str(self.controller.getIDCount()).zfill(8))

        # 设置客户名称列表
        customers = self.controller.customers
        for name in customers:
            self.customer.addItem(name)
        self.customer.setCurrentIndex(-1)
        self.customer.setEditable(False)
        # QCompleter.PopupCompletion 内容相关才显示
        # self.customer.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        # self.customer.setCompleter(self.customer.completer)

    def bindEvents(self):
        self.id.editingFinished.connect(self._setCountID)
        self.customer.currentIndexChanged.connect(self._nameChanged)
        self.btnClearItems.clicked.connect(self._onClearItemsClicked)

    def __getitem__(self, itemName):
        if itemName in INFO:
            if itemName == 'date':
                return self.date.dateTime().toString("yyyy年MM月dd日")
            ui = getattr(self, itemName)
            if isinstance(ui, QLineEdit):
                return ui.text()
            elif isinstance(ui, QComboBox):
                return ui.currentText()

    def getDate(self):
        return self.date.date()

    def getInfo(self):
        return {key: self[key] for key in INFO}

    def getCustomer(self):
        return self.customer.currentText()

    def getItems(self):
        items = []
        for uiItem in self.items:
            if uiItem.name.text().strip() is not None and uiItem.name.text().strip() != '':
                item = {key: uiItem[key] for key in ITEM}
                items.append(item)
        return items

    def _nameChanged(self):
        name = self.customer.currentText()
        self.onNameChanged.send(name)
        self.goods.setText(name)
        self.showTableView()

    def _clearItems(self):
        for uiItem in self.items:
            uiItem.clear()

    def _onClearItemsClicked(self):
        if showMessageBox("确定要清空数据吗？"):
            self._clearItems()

    def _setCountID(self):
        text = self.id.text()
        if text.isnumeric():
            self.controller.setIDCount(int(text))
        else:
            self.controller.setIDCount(1)

    # def calcAll(self):
    #     for uiItem in self.items:
    #         result = uiItem.calcPrice()
    #         if not result:
    #             return False

    '''
        响应外部方法
    '''
    def onAddCustomer(self, name):
        self.customer.addItem(name)

    def onSave(self):
        self.showTableView()
        self._clearItems()
        return True

    def onIDChanged(self, count):
        self.id.setText(str(count).zfill(8))

    def onRefreshSumUI(self, sum, sumMonth):
        self.sumPrice.setText("总计：\n" + str(sum))
        self.sumPriceMonth.setText("本月总计：\n" + str(sumMonth))

    def showTableView(self):
        csvModel = self.controller.getCsvModel()
        if csvModel is not None:
            self.tableView.setModel(csvModel)